namespace MiniCompiler
{
  /*!
  ** Check if we are in global scope or not.
  **
  ** @return If in global scope
  */
  inline bool
  ASMGeneratorVisitor::declaringGlobalVar() const
  {
    return _scope.size() <= 1;
  }

  /*!
  ** Set if we need to print the prelude.
  **
  ** @param hasToBePrint If prelude has to be print
  */
  inline void
  ASMGeneratorVisitor::printPrelude(bool hasToBePrint)
  {
    _printPrelude = hasToBePrint;
  }

  /*!
  ** Just Write the prelude, ie some function needed to make it works.
  **
  */
  inline void
  ASMGeneratorVisitor::writeHeader()
  {
    _indent << ";; Generated by Cubs\n\n";
    if (_printPrelude)
      _indent << ";\n"
	"; Linux C doesn't put underscores on labels\n"
	";\n"
	"%ifdef ELF_TYPE\n"
	"  %define _scanf   scanf\n"
	"  %define _printf  printf\n"
	"  %define _getchar getchar\n"
	"  %define _putchar putchar\n"
	"  %define _malloc malloc\n"
	"  %define _free free\n"
	"%endif\n"
	"\n"
	";\n"
	"; Watcom puts underscores at end of label\n"
	";\n"
	"%ifdef WATCOM\n"
	"  %define _scanf   scanf_\n"
	"  %define _printf  printf_\n"
	"  %define _getchar getchar_\n"
	"  %define _putchar putchar_\n"
	"  %define _malloc malloc_\n"
	"  %define _free free_\n"
	"%endif\n"
	"\n"
	"\n";
    _indent << "section .data\n"
      "\t_int_format db \"%i\", 0\n"
      "\t_string_format db \"%s\", 0\n"
      "\t_empty db \"\", 0\n"
      "\ttrue db \"true\", 0\n"
      "\tfalse db \"false\", 0\n";
  }

  /*!
  ** Just Write the prelude, ie some function needed to make it works.
  **
  */
  inline void
  ASMGeneratorVisitor::writePrelude()
  {
    if (!_printPrelude)
      return;

    _indent << "\n;; === PRELUDE ==\n\n"
      // read_int
      "__read_int:\n"
      "\tenter\t4,0\n"
      "\tpusha\n"
      "\tpushf\n"
      "\n"
      "\tlea\teax, [ebp-4]\n"
      "\tpush\teax\n"
      "\tpush\tdword _int_format\n"
      "\tcall\t_scanf\n"
      "\tpop\tecx\n"
      "\tpop\tecx\n"
      "\n"
      "\tpopf\n"
      "\tpopa\n"
      "\tmov\teax, [ebp-4]\n"
      "\tleave\n"
      "\tret\n"
      "\n"
      // print_int
      "__print_int:\n"
      "\tenter\t0,0\n"
      "\tpusha\n"
      "\tpushf\n"
      "\n"
      "\tpush\teax\n"
      "\tpush\tdword _int_format\n"
      "\tcall\t_printf\n"
      "\tpop\tecx\n"
      "\tpop\tecx\n"
      "\n"
      "\tpopf\n"
      "\tpopa\n"
      "\tleave\n"
      "\tret\n"
      "\n"
      // print_string
      "__print_string:\n"
      "\tenter\t0,0\n"
      "\tpusha\n"
      "\tpushf\n"
      "\n"
      "\tpush\teax\n"
      "\tpush\tdword _string_format\n"
      "\tcall\t_printf\n"
      "\tpop\tecx\n"
      "\tpop\tecx\n"
      "\n"
      "\tpopf\n"
      "\tpopa\n"
      "\tleave\n"
      "\tret\n"
      "\n"
      // read_char
      "__read_char:\n"
      "\tenter\t4,0\n"
      "\tpusha\n"
      "\tpushf\n"
      "\n"
      "\tcall\t_getchar\n"
      "\tmov\t[ebp-4], eax\n"
      "\n"
      "\tpopf\n"
      "\tpopa\n"
      "\tmov\teax, [ebp-4]\n"
      "\tleave\n"
      "\tret\n"
      "\n"
      // print_char
      "__print_char:\n"
      "\tenter\t0,0\n"
      "\tpusha\n"
      "\tpushf\n"
      "\n"
      "%ifndef WATCOM\n"
      "\tpush\teax\n"
      "%endif\n"
      "\tcall\t_putchar\n"
      "%ifndef WATCOM\n"
      "\tpop\tecx\n"
      "%endif\n"
      "\n"
      "\tpopf\n"
      "\tpopa\n"
      "\tleave\n"
      "\tret\n"
      "\n"
      // is_eq
      "__is_eq:\t\t\t; Check if first == second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\teax, 0\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tcmp\tebx, [ebp + 12]\n"
      "\tjne\t.quit\n"
      "\tmov\teax, 1\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      // is_diff
      "__is_diff:\t\t\t; Check if first != second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\teax, 0\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tcmp\tebx, [ebp + 12]\n"
      "\tje\t.quit\n"
      "\tmov\teax, 1\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      // is_sup
      "__is_sup:\t\t\t; Check if first > second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\teax, 0\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tcmp\tebx, [ebp + 12]\n"
      "\tjs\t.quit\n"
      "\tje\t.quit\n"
      "\tmov\teax, 1\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      // is_supeq
      "__is_supeq:\t\t\t; Check if first >= second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\teax, 0\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tcmp\tebx, [ebp + 12]\n"
      "\tjs\t.quit\n"
      "\tmov\teax, 1\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      // is_inf
      "__is_inf:\t\t\t; Check if first < second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\teax, 0\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tcmp\tebx, [ebp + 12]\n"
      "\tjns\t.quit\n"
      "\tmov\teax, 1\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      // is_infeq
      "__is_infeq:\t\t\t; Check if first <= second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\teax, 1\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tcmp\tebx, [ebp + 12]\n"
      "\tje\t.quit\n"
      "\tjs\t.quit\n"
      "\tmov\teax, 0\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      // print_bool
      "__print_bool:\t\t\t; Print a boolean stored in eax\n"
      "\ttest\teax, eax\n"
      "\tjz\t.false\n"
      "\tmov\teax, true\n"
      "\tjmp\t.true\n"
      "\t.false:\n"
      "\tmov\teax, false\n"
      "\t.true:\n"
      "\tcall\t__print_string\n"
      "\tret\n"
      // strlen
      "__strlen:\t\t\t; Compute the string length contained in eax,\n"
      "\t\t\t\t; and store it in eax\n"
      "\txor\tebx, ebx\n"
      ".loop:\n"
      "\tcmp\tbyte [eax], 0\n"
      "\tje\t.quit\n"
      "\tinc\tebx\n"
      "\tinc\teax\n"
      "\tjmp\t.loop\n"
      "\n"
      ".quit:\n"
      "\tmov\teax, ebx\n"
      "\tret\n"
      "\n"
      // concat
      "__concat:\t\t\t; Concat strings in eax and ebx\n"
      "\n"
      "\tmov\teax, edi\n"
      "\tcall\t__strlen\t\t; Get first size\n"
      "\tmov\tecx, eax\n"
      "\tmov\teax, esi\n"
      "\tcall\t__strlen\t\t; Get second size\n"
      "\tadd\tecx, eax\n"
      "\tinc\tecx\t\t; One more space for the \\0\n"
      "\tmov\teax, ecx\n"
      "\tcall\tmalloc\t\t; Allocate needed space\n"
      "\tmov\tedx, eax\t; Make copy of the returned adress\n"
      "\n"
      "\tmov\tecx, edi\t; Copy the first string\n"
      ".loop1:\n"
      "\tcmp\tbyte [ecx], 0\n"
      "\tje\t.stop1\n"
      "\tmov\tebx, [ecx]\n"
      "\tmov\t[edx], ebx\n"
      "\tinc\tedx\n"
      "\tinc\tecx\n"
      "\tjmp\t.loop1\n"
      ".stop1:\n"
      "\n"
      "\tmov\tecx, esi\t; Copy the second string\n"
      ".loop2:\n"
      "\tcmp\tbyte [ecx], 0\n"
      "\tje\t.stop2\n"
      "\tmov\tebx, [ecx]\n"
      "\tmov\t[edx], ebx\n"
      "\tinc\tedx\n"
      "\tinc\tecx\n"
      "\tjmp\t.loop2\n"
      ".stop2:\n"
      "\n"
      "\tmov\tbyte [edx], 0\t; Add final \\0\n"
      "\n"
      "\tret\n"
      "\n"
      // streq
      "__streq:\t\t\t; Check if first == second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tmov\tedx, [ebp + 12]\n"
      "\txor\teax, eax\n"
      "\n"
      ".loop:\n"
      "\tcmp\tbyte [ebx], 0\n"
      "\tje\t.end\n"
      "\tmov\tcl, [ebx]\n"
      "\tcmp\t[edx], cl\n"
      "\tjne\t.quit\n"
      "\tinc\tebx\n"
      "\tinc\tedx\n"
      "\tjmp\t.loop\n"
      ".end:\n"
      "\tmov\tcl, [ebx]\n"
      "\tcmp\t[edx], cl\n"
      "\tjne\t.quit\n"
      "\tinc\teax\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      "\n"
      // strdiff
      "__strdiff:\t\t\t; Check if first != second\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\tmov\tebx, [ebp + 8]\n"
      "\tmov\tedx, [ebp + 12]\n"
      "\tmov\teax, 1\n"
      "\n"
      ".loop:\n"
      "\tcmp\tbyte [ebx], 0\n"
      "\tje\t.end\n"
      "\tmov\tcl, [ebx]\n"
      "\tcmp\t[edx], cl\n"
      "\tjne\t.quit\n"
      "\tinc\tebx\n"
      "\tinc\tedx\n"
      "\tjmp\t.loop\n"
      ".end:\n"
      "\tmov\tcl, [ebx]\n"
      "\tcmp\t[edx], cl\n"
      "\tjne\t.quit\n"
      "\txor\teax, eax\n"
      ".quit:\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      "\n"
      // read_bool
      "__read_bool:\n"
      "\tcall\t__read_int\n"
      "\tret\n"
      "\n"
      // rad_string
      "__read_string:\n"
      "\tpush\tebp\n"
      "\tmov\tebp, esp\n"
      "\n"
      "\txor\tecx, ecx\n"
      "\tpush\tdword 0\n"
      ".loop:\n"
      "\tcall\t__read_char\n"
      "\tcmp\teax, 10\t\t; When \\n, stop to get char\n"
      "\tje\t.stop\n"
      "\tpush\teax\n"
      "\tinc\tecx\n"
      "\tjmp\t.loop\n"
      ".stop:\n"
      "\tinc\tecx\t\t; Add the space for the final \\0\n"
      "\tpush\tecx\n"
      "\tmov\teax, ecx\n"
      "\tcall\tmalloc\n"
      "\tmov\tedx, eax\t; Make a copy of eax, and don't touch it\n"
      "\tpop\tecx\n"
      "\tadd\tedx, ecx\t; Go back to the end of the string, then\n"
      "\tdec\tedx\n"
      "\tmov\tbyte [edx], 0\t; Put the final \\0\n"
      ".loop2:\n"
      "\tcmp\tecx, 0\t\t; Just copy all char, poping them all\n"
      "\tje\t.quit\n"
      "\tdec\tecx\n"
      "\tpop\tebx\n"
      "\tdec\tedx\n"
      "\tmov\t[edx], bl\n"
      "\tjmp\t.loop2\n"
      ".quit:\t\t\t\t; Eax will be setted with string\n"
      "\tmov\tesp, ebp\n"
      "\tpop\tebp\n"
      "\tret\n"
      "\n"
      // End Prelude
      ";; === END PRELUDE ==\n\n";
  }

  /*!
  ** Just Write the Postlude, ie all read-only strings.
  **
  */
  inline void
  ASMGeneratorVisitor::writePostlude()
  {
    if (_strings.size () > 0)
      _indent << "\nsection .data\n";
    for (ROStrings::const_iterator it = _strings.begin();
	 it != _strings.end(); ++it)
    {
      _indent << "\t" << it->second << " db \"" << it->first << "\", 0\n";
    }
  }
}
